
#include "StdAfx.h"
#include "CWAManager.h"
#include "../Inc/bt_ui.h"
#include "../Inc/bt_def.h"
#include "../Common/CommonFun.h"
#include "../Res/resource.h"
#include "../Common/CommonDef.h"
#include "PROCESS.H"
#include "CWADevice.h"
#include "../Frame/GYWalkAidApp.h"
#include "../Frame/CustomMsgCenter.h"

extern volatile BOOL g_bAppQuit;

#define CONNECT_TRY_TIME_COUNT		50
#define START_GAIT_TRY_TIME_COUNT	3

#define BYTE_IS(n, b)	(aDataGet[n] == 0x##b)

#define HI_BYTE(b)		(b >> 4)
#define LOW_BYTE(b)		(b & 0x0f)

#define	DATA		0x00
#define BNUM		0x00

#define CHECK_VECTOR_INDEX_STRING(vec, idx)	{if(vec.empty() || idx >= vec.size()) return _T("");}
#define CHECK_VECTOR_INDEX_NUMBER(vec, idx)	{if(vec.empty() || idx >= vec.size()) return 0;}
#define CHECK_VECTOR_INDEX_STRUCT(vec, idx , STRUCT)	{if(vec.empty() || idx >= vec.size()){STRUCT a; memset(&a,0,sizeof(STRUCT)); return a;}}

#define PARAM_BIT_FREQ		0x01
#define PARAM_BIT_WIDTH		0x02
#define PARAM_BIT_COUNT		0x04
#define PARAM_BIT_OPEN		0x08
#define PARAM_BIT_CLOSE		0x10
#define PARAM_BIT_UP		0x20
#define PARAM_BIT_DOWN		0x40

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Commands
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DWORD CWAManager::cmdReadCommVersion(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);

	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	BYTE aCmdSent[] = {0x2a, 0x55, 0x00, 0x23};
	BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};

	pDevice->ClearBufFromCOM();
	pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);

	DWORD dwVer = 0;
	
	if( BYTE_IS(0, 2a) && 
		BYTE_IS(1, 55) && 
		BYTE_IS(2, 01) && 
		BYTE_IS(4, 23) )
	{
		dwVer = aDataGet[3];
	}

	pDevice->SetCommVersion(dwVer);
	return dwVer;
}

CString CWAManager::cmdReadFirmwareVer(int nDevIndex)
{
	CHECK_VECTOR_INDEX_STRING(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_EMPTY(pDevice);
	
	BYTE aCmdSent[] = {0x2a, 0x54, 0x00, 0x23};
	BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, DATA, DATA, 0x00};
	
	for(int i = 1; i <= 5; i++)
	{
		pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 200 * i);
		
		CString strVer;
		strVer.Format(_T("V%d.%d.%d%d%d"), aDataGet[3]>>4, aDataGet[3] & 0x0f, aDataGet[4]>>4, aDataGet[4] & 0x0f, aDataGet[5]>>4);

		if(aDataGet[2] == 0x03)
			return strVer;
	}

	return _T("");
}


BOOL CWAManager::cmdConnectWA(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_FALSE(pDevice);

	pDevice->ClearBufFromCOM();

	DWORD dwVer = GetWACommVersion(nDevIndex);
	switch(dwVer)
	{
	case 0x01:
		{
			BYTE aCmdSent[] = {0x2a, 0x80, 0x00, 0x23};
			BYTE aDataGet[] = {0x2a};

			for(int i = 0; i < CONNECT_TRY_TIME_COUNT; i++)
			{
				WA_BASIC_PARA wbp = cmdGetBasicPara(nDevIndex);
				if(wbp.dwSize == sizeof(WA_BASIC_PARA))
				{
					pDevice->SetConnectedWA(TRUE);
					return TRUE;
				}

				pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, 0, 100);// no wait, because expected lenth is 0
				
				::Sleep(500);
				pDevice->ClearBufFromCOM();
			}
		}
		break;

	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 0x82, 0x01, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, DATA, 0x00};

			for(int i = 0; i < CONNECT_TRY_TIME_COUNT; i++)
			{
				pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);
				
				if( BYTE_IS(0, 2a) && 
					BYTE_IS(1, 82) && 
					BYTE_IS(2, 01) && 
					BYTE_IS(3, 23) )
				{
					pDevice->SetConnectedWA(TRUE);
					return TRUE;
				}

				::Sleep(200);
				pDevice->ClearBufFromCOM();
				
				//  if get data OK, connected
				WA_BASIC_PARA wbp = cmdGetBasicPara(nDevIndex);
				if(wbp.dwSize == sizeof(WA_BASIC_PARA))
				{
					pDevice->SetConnectedWA(TRUE);
					return TRUE;
				}

				aCmdSent[0] = 0x2a;
				aCmdSent[1] = 0x81;
				aCmdSent[2] = 0x00;
				aCmdSent[3] = 0x23;

				aDataGet[0] = 0x00;
				aDataGet[1] = 0x00;
				aDataGet[2] = DATA;
				aDataGet[3] = 0x00;

				pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);	//  NOT to check the return data is OK

				::Sleep(500);
				pDevice->ClearBufFromCOM();
			}
		}
		break;

	case 0x12:  //  1.2
		{
			BYTE aCmdSent[] = {0x2a, 0x56, 0x00, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, DATA, 0x00};

			for(int i = 0; i < CONNECT_TRY_TIME_COUNT; i++)
			{
				pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);
				
				if( BYTE_IS(0, 2a) && 
					BYTE_IS(1, 56) && 
					BYTE_IS(2, 01) && 
					BYTE_IS(3, 23) )
				{
					pDevice->SetConnectedWA(TRUE);
					return TRUE;
				}
				
				::Sleep(500);
				pDevice->ClearBufFromCOM();
			}
		}
		break;
	}

	return FALSE;
}

BOOL CWAManager::cmdDisconnectWA(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_FALSE(pDevice);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:	//  always connect
		return TRUE;
		
	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 81, 0x01, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, 0, 500);
			pDevice->SetConnectedWA(FALSE);
			return TRUE;
		}
		break;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x57, 0x00, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);
			pDevice->SetConnectedWA(FALSE);
			return (aDataGet[2] == 0x01);
		}
		break;
	}
	
	return FALSE;
}

DWORD CWAManager::cmdGetBattery(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		ASSERT("No battery interface" == NULL);
		break;

	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x33, 0x00, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};

			//  read battery 3 times, save the average one
			DWORD dwTotalBattery = 0;
			for(int i = 0; i < 3; i++)
			{
				pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 200);
				
				if( BYTE_IS(0, 2a) && 
					BYTE_IS(1, 33) && 
					BYTE_IS(2, 01) && 
					BYTE_IS(4, 23) )
				{
					dwTotalBattery += aDataGet[3];
				}

				if(i < 2)
					Sleep(200);
			}

			double dTotalBattery = dwTotalBattery + 0.9;
			DWORD dwBattery = (DWORD)(dTotalBattery / 3);

			dwBattery = min(dwBattery, 4);
			dwBattery = max(dwBattery, 0);

			return dwBattery;
		}
		break;
	}
	
	return 0;
}

WA_BASIC_PARA CWAManager::cmdGetBasicPara(int nDevIndex)
{
	CHECK_VECTOR_INDEX_STRUCT(m_vecWADevice, nDevIndex, WA_BASIC_PARA);

	WA_BASIC_PARA wbp = {0};
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	if(pDevice == NULL)
		return wbp;

	pDevice->ClearBufFromCOM();

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BYTE aCmdSent[] = { 0x2a, 0x01, 0x00, 0x23};
			BYTE aDataGet[] = { 0x00, 0x00, DATA, 0x00, 
								0x00, 0x00, DATA, 0x00, 
								0x00, 0x00, DATA, 0x00, 
								0x00, 0x00, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);

			int nCmdSuccCount = 0;
			
			int nCmdBegin = 0;
			while(nCmdBegin < sizeof(aDataGet))
			{
				if(	BYTE_IS(nCmdBegin,		2a) &&
					BYTE_IS(nCmdBegin + 3,	23)	)
				{
					switch(aDataGet[nCmdBegin + 1])
					{
					case 0x02:
						wbp.dwStiDownTime	= aDataGet[nCmdBegin + 2];
						
						nCmdSuccCount++;
						break;
						
					case 0x04:
						wbp.dwStiUpTime		= aDataGet[nCmdBegin + 2];
						
						nCmdSuccCount++;
						break;
						
					case 0x08:
						wbp.dwCloseThr		= aDataGet[nCmdBegin + 2];
						
						nCmdSuccCount++;
						break;

					case 0x20:
						wbp.dwOpenThr		= aDataGet[nCmdBegin + 2];
						
						nCmdSuccCount++;
						break;
					}
					
					nCmdBegin += 4;
				}
				else
				{
					ASSERT(_T("Cmd is not begined with 0x2a and ended with 0x23") == 0);
					break;
				}
			}
			
			if(nCmdSuccCount == 4)
			{
				//  Success !
				wbp.dwSize = sizeof(WA_BASIC_PARA);

				//  0.1 and 0.2 version, the 3 params is fixed
				wbp.dwPulseFrq		= 4;
				wbp.dwPulseWidth	= 2;
				wbp.dwPulseCount	= 17;
			}
		}
		break;
		
	case 0x12:
		{
			BYTE aCmdSent[] = { 0x2a, 0x19, 0x00, 0x23};
			BYTE aDataGet[] = { 0x00, 0x00, BNUM, DATA, DATA, DATA, DATA, DATA, DATA, 0x00,		// time
								0x00, 0x00, BNUM, DATA, 0x00,									// open
								0x00, 0x00, BNUM, DATA, 0x00,									// close
								0x00, 0x00, BNUM, DATA, 0x00,									// up
								0x00, 0x00, BNUM, DATA, 0x00,									// down
								0x00, 0x00, BNUM, DATA, 0x00,									// repeat frequency
								0x00, 0x00, BNUM, DATA, 0x00,									// pulse width
								0x00, 0x00, BNUM, DATA, 0x00};									// pulse count
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);

			int nCmdSuccCount = 0;

			int nCmdBegin = 0;
			while(nCmdBegin < sizeof(aDataGet))
			{
				if(BYTE_IS(nCmdBegin, 2a))
				{
					int nCmdBytes = aDataGet[nCmdBegin + 2];
					if(BYTE_IS(nCmdBegin + nCmdBytes + 3, 23))
					{
						switch(aDataGet[nCmdBegin + 1])
						{
						case 0x22:
							wbp.dwYear			= aDataGet[nCmdBegin + 3];
							wbp.dwMonth			= aDataGet[nCmdBegin + 4];
							wbp.dwDay			= aDataGet[nCmdBegin + 5];
							wbp.dwWeek			= aDataGet[nCmdBegin + 6];
							wbp.dwHour			= aDataGet[nCmdBegin + 7];
							wbp.dwMinute		= aDataGet[nCmdBegin + 8];

							nCmdSuccCount++;
							break;

						case 0x11:
							wbp.dwOpenThr		= aDataGet[nCmdBegin + 3];
							
							nCmdSuccCount++;
							break;
							
						case 0x12:
							wbp.dwCloseThr		= aDataGet[nCmdBegin + 3];
							
							nCmdSuccCount++;
							break;

						case 0x13:
							wbp.dwStiUpTime		= aDataGet[nCmdBegin + 3];
							
							nCmdSuccCount++;
							break;
							
						case 0x14:
							wbp.dwStiDownTime	= aDataGet[nCmdBegin + 3];
							
							nCmdSuccCount++;
							break;
							
						case 0x15:
							wbp.dwPulseFrq		= aDataGet[nCmdBegin + 3];
							
							nCmdSuccCount++;
							break;
							
						case 0x16:
							wbp.dwPulseWidth	= aDataGet[nCmdBegin + 3];
							
							nCmdSuccCount++;
							break;
							
						case 0x17:
							wbp.dwPulseCount	= aDataGet[nCmdBegin + 3];
							
							nCmdSuccCount++;
							break;
						}

						nCmdBegin += (nCmdBytes + 4);
					}
					else
					{
						ASSERT(_T("Cmd is not ended with 0x23") == 0);
						break;
					}
				}
				else
				{
					ASSERT(_T("Cmd is not begined with 0x2a") == 0);
					break;
				}
			}

			if(nCmdSuccCount == 8)
			{
				//  Success !
				wbp.dwSize = sizeof(WA_BASIC_PARA);
			}
		}
		break;
	}

	return wbp;
}

BOOL CWAManager::cmdWriteBasicPara(int nDevIndex, WA_BASIC_PARA wbp)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_FALSE(pDevice);

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BOOL bRet1 = cmdWriteTriggerOpen(nDevIndex, wbp.dwOpenThr);
			Sleep(200);

			BOOL bRet2 = cmdWriteTriggerClose(nDevIndex, wbp.dwCloseThr);
			Sleep(200);

			BOOL bRet3 = cmdWriteStiUpTime(nDevIndex, wbp.dwStiUpTime);
			Sleep(200);
			
			DWORD dwRet4 = cmdWriteStiDownTime(nDevIndex, wbp.dwStiDownTime);

			return (bRet1 && bRet2 && bRet3 && dwRet4 != 0x00);
		}

	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x29, 0x07, DATA, DATA, DATA, DATA, DATA, DATA, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};

			aCmdSent[3] = wbp.dwPulseFrq;
			aCmdSent[4] = wbp.dwPulseWidth;
			aCmdSent[5] = wbp.dwPulseCount;
			aCmdSent[6] = wbp.dwOpenThr;
			aCmdSent[7] = wbp.dwCloseThr;
			aCmdSent[8] = wbp.dwStiUpTime;
			aCmdSent[9] = wbp.dwStiDownTime;

			pDevice->ClearBufFromCOM();
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 550);

			return (BYTE_IS(0, 2a) &&
					BYTE_IS(1, 29) &&
					BYTE_IS(2, 01) &&
					BYTE_IS(3, 01) &&
					BYTE_IS(4, 23) );
		}
	}

	return FALSE;
}

BOOL CWAManager::cmdWriteParamOCD(int nDevIndex, WA_BASIC_PARA wbpOpenCloseDown)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_FALSE(pDevice);
	
	pDevice->ClearBufFromCOM();

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BOOL bRet1 = cmdWriteTriggerOpen(nDevIndex, wbpOpenCloseDown.dwOpenThr);
			Sleep(300);
			
			BOOL bRet2 = cmdWriteTriggerClose(nDevIndex, wbpOpenCloseDown.dwCloseThr);
			Sleep(300);

			WA_BASIC_PARA wbpResult = cmdGetBasicPara(nDevIndex);
			if( wbpResult.dwSize	== sizeof(WA_BASIC_PARA)		&&
				wbpResult.dwOpenThr	== wbpOpenCloseDown.dwOpenThr	&& 
				wbpResult.dwCloseThr== wbpOpenCloseDown.dwCloseThr	)
			{
				return TRUE;
			}
		}
		break;

	case 0x12:
		{
			BOOL bRet1 = cmdWriteTriggerOpen(nDevIndex, wbpOpenCloseDown.dwOpenThr);
			Sleep(300);
			
			BOOL bRet2 = cmdWriteTriggerClose(nDevIndex, wbpOpenCloseDown.dwCloseThr);
			Sleep(300);

			DWORD dwRet = cmdWriteStiDownTime(nDevIndex, wbpOpenCloseDown.dwStiDownTime);

			return (dwRet == (PARAM_BIT_OPEN|PARAM_BIT_CLOSE|PARAM_BIT_DOWN));
		}
		break;
	}

	return FALSE;
}

CString	CWAManager::cmdReadWADevID(int nDevIndex)
{
	CHECK_VECTOR_INDEX_STRING(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_EMPTY(pDevice);
	
	if(GetWACommVersion(nDevIndex) == 0x01)
		return pDevice->GetAddress();

	BYTE aCmdSent[] = {0x2a, 0x23, 0x00, 0x23};
	BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, DATA, DATA, DATA, DATA, 0x00};

	//  try 3 times
	for(int i = 0; i < 3; i++)
	{
		pDevice->ClearBufFromCOM();
		pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);
		
		if( BYTE_IS(0, 2a) && 
			BYTE_IS(1, 23) && 
			BYTE_IS(2, 05) && 
			BYTE_IS(8, 23) )
		{
			CString strDevID;
			strDevID.Format(_T("%X%X%X%X%X%X%X%X%X%X"), HI_BYTE(aDataGet[3]), LOW_BYTE(aDataGet[3]), HI_BYTE(aDataGet[4]), LOW_BYTE(aDataGet[4]), HI_BYTE(aDataGet[5]), LOW_BYTE(aDataGet[5]), HI_BYTE(aDataGet[6]), LOW_BYTE(aDataGet[6]), HI_BYTE(aDataGet[7]), LOW_BYTE(aDataGet[7]));
			return strDevID;
		}

		if(i < 2)
			Sleep(200);
	}

	return _T("");
}

BOOL CWAManager::cmdStartReadGait(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_FALSE(pDevice);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 0x10, 0x00, 0x23};
			BYTE aDataGet[] = {DATA, DATA};

			//  try 3 times
			for(int i = 0; i < START_GAIT_TRY_TIME_COUNT; i++)
			{
				pDevice->ClearBufFromCOM();
				BOOL bRet = pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);

				if(bRet)
				{
					pDevice->SetReadingGaitStart(TRUE);
					return TRUE;
				}

				if(i < (START_GAIT_TRY_TIME_COUNT -1))
					Sleep(200);
			}
		}
		break;

	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x31, 0x00, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};

			//  try 3 times
			for(int i = 0; i < START_GAIT_TRY_TIME_COUNT; i++)
			{
				pDevice->ClearBufFromCOM();
				pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);

				if( BYTE_IS(0, 2a) && 
					BYTE_IS(1, 31) && 
					BYTE_IS(2, 01) && 
					BYTE_IS(4, 23) )
				{
					pDevice->SetReadingGaitStart(TRUE);
					return TRUE;
				}

				if(i < (START_GAIT_TRY_TIME_COUNT -1))
					Sleep(200);
			}
		}
		break;

	default:
		return FALSE;
	}

	return FALSE;
}

BOOL CWAManager::cmdStopReadGait(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_FALSE(pDevice);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 0x40, 0x00, 0x23};
			BYTE aDataGet[] = {0x2a};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, 0, 500); //  no data return
			pDevice->ClearBufFromCOM();
			pDevice->SetReadingGaitStart(FALSE);
		}
		break;
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x32, 0x00, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 500);
			pDevice->ClearBufFromCOM();
			pDevice->SetReadingGaitStart(FALSE);
			return (aDataGet[2] == 0x01);
		}
		break;
		
	default:
		return FALSE;
	}

	
	return TRUE;
}

DWORD CWAManager::cmdReadGaitValue(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	if(!pDevice->IsReadingGaitStart())
		return 0;

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a};
			BYTE aDataGet[] = {DATA, DATA};
			
			pDevice->ExecuteCmd(aCmdSent, 0, aDataGet, sizeof(aDataGet), 600); //  no data sent
			return aDataGet[0];
		}
		break;
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, 0, aDataGet,  sizeof(aDataGet), 600); //  no data sent
			return aDataGet[3];
		}
		break;
		
	default:
		return FALSE;
	}

	return 0;
}

DWORD CWAManager::cmdReadMRNCode(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return 0;

	case 0x12:
		{
			pDevice->ClearBufFromCOM();

			BYTE aCmdSent[] = {0x2a, 0x44, 0x00, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 500);
			if(aDataGet[2] == 0x02)
			{
				DWORD dwRet = 0;
				dwRet |= aDataGet[4];
				dwRet |= (aDataGet[3] << 8);

				return dwRet;
			}
		}
		break;
	}

	return 0;
}

BOOL CWAManager::cmdWriteMRNCode(int nDevIndex, DWORD dwMRNCode)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return FALSE;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x43, 0x02, DATA, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[3] = (BYTE)((dwMRNCode & 0x3f00) >> 8);
			aCmdSent[4] = (BYTE)(dwMRNCode & 0xff);

			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 500);

			if( BYTE_IS(0, 2a) && 
				BYTE_IS(1, 43) && 
				BYTE_IS(2, 01) && 
				BYTE_IS(4, 23) )
			{
				if(aDataGet[3] == 0x01)
					return TRUE;
			}
		}
		break;
	}
	
	return FALSE;
}

DWORD CWAManager::cmdWriteStiDownTime(int nDevIndex, DWORD dwDownTime)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	BYTE byteStiTime = (BYTE)(dwDownTime & 0xff);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
		{
			BYTE aCmdSent[] = {0x2a, 0x02, DATA, 0x23};
			BYTE aDataGet[] = {0x00};
			
			aCmdSent[2] = byteStiTime;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, 0, 200);// no return
			return 0;
		}
		break;

	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 0x02, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[2] = byteStiTime;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 200);
			if( BYTE_IS(0, 2a) && 
				BYTE_IS(1, 02) && 
				BYTE_IS(2, 01) && 
				BYTE_IS(3, 01) && 
				BYTE_IS(4, 23) )
			{
				return 1;
			}
		}
		break;

	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x14, 0x01, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[3] = byteStiTime;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, sizeof(aDataGet), 500);
			return aDataGet[3];
		}
		break;
	}
	
	return 0;
}

BOOL CWAManager::cmdWriteStiUpTime(int nDevIndex, DWORD dwUpTime)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	BYTE byteStiTime = (BYTE)(dwUpTime & 0xff);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 0x04, DATA, 0x23};
			BYTE aDataGet[] = {0x00};
			
			aCmdSent[2] = byteStiTime;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  0, 200);// no return
			return TRUE;
		}
		break;

	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x13, 0x01, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[3] = byteStiTime;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 500);
			if(aDataGet[3] != 0x00)
				return TRUE;
		}
		break;
	}
	
	return FALSE;
}

BOOL CWAManager::cmdWriteTriggerClose(int nDevIndex, DWORD dwClose)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	BYTE ucClose = (BYTE)(dwClose & 0xff);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 0x08, DATA, 0x23};
			BYTE aDataGet[] = {0x00};
			
			aCmdSent[2] = ucClose;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, 0, 200);// no return
			return TRUE;
		}
		break;
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x12, 0x01, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[3] = ucClose;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet, 0, 200);	// no return
			return TRUE;
		}
		break;
	}
	
	return FALSE;
}

BOOL CWAManager::cmdWriteTriggerOpen(int nDevIndex, DWORD dwOpen)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	BYTE ucOpen = (BYTE)(dwOpen & 0xff);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		{
			BYTE aCmdSent[] = {0x2a, 0x20, DATA, 0x23};
			BYTE aDataGet[] = {0x00};
			
			aCmdSent[2] = ucOpen;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  0, 200);// no return
			return TRUE;
		}
		break;

	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x11, 0x01, DATA, 0x23};
			BYTE aDataGet[] = {0x00};
			
			aCmdSent[3] = ucOpen;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  0, 200);// no return
			return TRUE;
		}
		break;
	}
	
	return FALSE;
}

BOOL CWAManager::cmdWritePulseFreq	(int nDevIndex, DWORD dwPulseFreq)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	BYTE byteFreq = (dwPulseFreq & 0xFF);
	if(byteFreq < 3 || byteFreq > 6)
		return FALSE;
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return FALSE;

	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x15, 0x01, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[3] = byteFreq;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 500);
			if(aDataGet[3] != 0x00)
				return TRUE;
		}
		break;
	}
	
	return FALSE;
}

BOOL CWAManager::cmdWritePulseWidth	(int nDevIndex, DWORD dwPulseWidth)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	BYTE byteWidth = (dwPulseWidth & 0xFF);
	if(byteWidth < 1 || byteWidth > 5)
		return FALSE;
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return FALSE;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x16, 0x01, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[3] = byteWidth;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 500);
			if(aDataGet[3] != 0x00)
				return TRUE;
		}
		break;
	}
	
	return FALSE;
}

BOOL CWAManager::cmdWritePulseCount	(int nDevIndex, DWORD dwPulseCount)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	BYTE byteCount = (dwPulseCount & 0xFF);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return FALSE;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x17, 0x01, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			aCmdSent[3] = byteCount;
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 500);
			if(aDataGet[3] != 0x00)
				return TRUE;
		}
		break;
	}
	
	return FALSE;
}

BOOL CWAManager::cmdStartReadHistory(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	pDevice->ClearBufFromCOM();

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return FALSE;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x41, 0x00, 0x23};
			BYTE aDataGet[] = {DATA};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  0, 0); //  Data will be got with subsequent cmdReadHistoryData
			return TRUE;
		}
		break;
	}
	
	return FALSE;
}

WA_HISTORY_DATA CWAManager::cmdReadHistoryData(int nDevIndex)
{
	CHECK_VECTOR_INDEX_STRUCT(m_vecWADevice, nDevIndex, WA_HISTORY_DATA);

	WA_HISTORY_DATA whd;
	memset(&whd, 0, sizeof(WA_HISTORY_DATA));

	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	if(pDevice == NULL)
		return whd;

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return whd;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, DATA, DATA, DATA, DATA, DATA, DATA, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, 0, aDataGet,  sizeof(aDataGet), 600); //  no data sent
			if( BYTE_IS(0, 2a) && 
				BYTE_IS(1, 41) && 
				BYTE_IS(2, 08) && 
				BYTE_IS(11,23) )
			{
				DWORD dwStepLow		= aDataGet[9];

				DWORD dwStepHigh	= (aDataGet[8] & 0xC0);
					  dwStepHigh	= (dwStepHigh << 2);

				DWORD dwMRNCodeLow	= aDataGet[10];

				DWORD dwMRNCodeHigh	= (aDataGet[8] & 0x3f);
					  dwMRNCodeHigh	= (dwMRNCodeHigh << 8);

				whd.dwTimespan	= aDataGet[7] * 3;								// seconds, multiple 3
				whd.dwStepCount	= (dwStepHigh		| dwStepLow);
				whd.dwMRNCode	= (dwMRNCodeHigh	| dwMRNCodeLow);

				CTime tCur = CTime::GetCurrentTime();

				int nThisYear = tCur.GetYear();
				int nLastYear = nThisYear - 1;

				//  BCD code
				int nMonth	= GetBCDValue(aDataGet[3]);
				int nDay	= GetBCDValue(aDataGet[4]);
				int nHour	= GetBCDValue(aDataGet[5]);
				int nMinute = GetBCDValue(aDataGet[6]);

				if(IsValidDateTime(nThisYear, nMonth, nDay, nHour, nMinute, 0))
				{
					CTime tThisYearTime(nThisYear, nMonth, nDay, nHour, nMinute, 0);
					if(tThisYearTime < tCur)
					{
						whd.tTime	= tThisYearTime;
						whd.dwSize	= sizeof(WA_HISTORY_DATA);
					}
					else
					{
						if(IsValidDateTime(nLastYear, nMonth, nDay, nHour, nMinute, 0))
						{
							CTime tLastYearTime(nLastYear,	nMonth, nDay, nHour, nMinute, 0);

							whd.tTime	= tLastYearTime;
							whd.dwSize	= sizeof(WA_HISTORY_DATA);
						}
					}

				}
				else if(IsValidDateTime(nLastYear, nMonth, nDay, nHour, nMinute, 0))
				{
					CTime tLastYearTime(nLastYear,	nMonth, nDay, nHour, nMinute, 0);
					
					whd.tTime	= tLastYearTime;
					whd.dwSize	= sizeof(WA_HISTORY_DATA);
				}

				return whd;
			}
		}
		break;
	}
	
	return whd;
}

BOOL CWAManager::cmdClearHistoryData(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return FALSE;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x42, 0x00, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 600);
			return aDataGet[3] == 0x01;
		}
		break;
	}
	
	return FALSE;
}

BOOL CWAManager::cmdWriteWATime(int nDevIndex, WA_BASIC_PARA wbp)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	pDevice->ClearBufFromCOM();

	switch(GetWACommVersion(nDevIndex))
	{
	case 0x01:
	case 0x02:
		return FALSE;
		
	case 0x12:
		{
			BYTE aCmdSent[] = {0x2a, 0x21, 0x06, DATA, DATA, DATA, DATA, DATA, DATA, 0x23};
			BYTE aDataGet[] = {0x00, 0x00, BNUM, DATA, 0x00};

			aCmdSent[3]	= GetBCDByte(wbp.dwYear);
			aCmdSent[4]	= GetBCDByte(wbp.dwMonth);
			aCmdSent[5]	= GetBCDByte(wbp.dwDay);
			aCmdSent[6]	= GetBCDByte(wbp.dwWeek);
			aCmdSent[7]	= GetBCDByte(wbp.dwHour);
			aCmdSent[8]	= GetBCDByte(wbp.dwMinute);
			
			pDevice->ExecuteCmd(aCmdSent, sizeof(aCmdSent), aDataGet,  sizeof(aDataGet), 300);
			if( BYTE_IS(0, 2a) && 
				BYTE_IS(1, 21) && 
				BYTE_IS(2, 01) && 
				BYTE_IS(4, 23) )
			{
				return aDataGet[3] == 0x01;
			}
		}
		break;
	}

	return FALSE;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Construct & Init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CWAManager::CWAManager()
{
	m_hInquireThread			= NULL;
	m_hEventInquireWA			= CreateEvent(NULL, FALSE, TRUE, NULL);
	m_bInquireTimerStarted		= FALSE;
	m_bInquiringWA				= FALSE;

	InitializeCriticalSection(&m_csBluetoothToken);
	InitializeCriticalSection(&m_csVectorDevList);
}

CWAManager::~CWAManager()
{
	DeleteCriticalSection(&m_csBluetoothToken);
	DeleteCriticalSection(&m_csVectorDevList);
}

BOOL CWAManager::Init()
{
	GetApp()->GetCustMsgCenter()->RegCustomMsgProcess(GYWA_MSG_BLUETOOTH_DEVICE_CONNECTED,		this,	(MSG_PROCESS_FUNC)OnWAConnected);
	GetApp()->GetCustMsgCenter()->RegCustomMsgProcess(GYWA_MSG_BLUETOOTH_CONNECT_FAIL,			this,	(MSG_PROCESS_FUNC)OnWAConnectBTFail);
	GetApp()->GetCustMsgCenter()->RegTimerProcess(GYWA_MSG_BLUETOOTH_TIMERID_INQUIRE_WA,		this,	(MSG_PROCESS_FUNC)OnTimerInquireWA);

	return InquireWA();
}

BOOL CWAManager::Uninit()
{
	GetApp()->GetCustMsgCenter()->RemoveCustomMsgProcess(GYWA_MSG_BLUETOOTH_DEVICE_CONNECTED,	this,	(MSG_PROCESS_FUNC)OnWAConnected);
	GetApp()->GetCustMsgCenter()->RemoveCustomMsgProcess(GYWA_MSG_BLUETOOTH_CONNECT_FAIL,		this,	(MSG_PROCESS_FUNC)OnWAConnectBTFail);
	GetApp()->GetCustMsgCenter()->RemoveTimerProcess(GYWA_MSG_BLUETOOTH_TIMERID_INQUIRE_WA,		this,	(MSG_PROCESS_FUNC)OnTimerInquireWA);
	

// 	for(int i = 0; i < m_vecWADevice.size(); i++)
// 	{
// 		CWADevice* pDevice = m_vecWADevice[i];
// 		SAFE_DELETE(pDevice);
// 	}
// 	m_vecWADevice.clear();

	BT_StopBluetooth(3);

	return TRUE;
}

BOOL CWAManager::InquireWA()
{
	if(!InitBluetooth())
		return FALSE;

	UINT unThreadID				=0;
	m_hInquireThread			=(HANDLE)_beginthreadex(NULL,0, InquireBTDeviceThread, (LPVOID)this, 0, &unThreadID); 

	return TRUE;
}

BOOL CWAManager::WaitThreadsQuit()
{
	if(m_hInquireThread)
	{
		BT_CancelInquiry();

		SetEvent(m_hEventInquireWA);
		WaitForSingleObject(m_hInquireThread, 5000);
		
		CLOSE_HANDLE(m_hInquireThread);
		CLOSE_HANDLE(m_hEventInquireWA);
	}

	EnterCriticalSection(&m_csVectorDevList);

	for(int i = 0; i < m_vecWADevice.size(); i++)
	{
		if(m_vecWADevice[i])
		{
			m_vecWADevice[i]->UninitDev();
			SAFE_DELETE(m_vecWADevice[i]);
		}
	}

	m_vecWADevice.clear();

	LeaveCriticalSection(&m_csVectorDevList);

	BT_UninitializeLibrary();
	return TRUE;
}

BOOL CWAManager::InitBluetooth()
{
	if(!BT_IsBlueSoleilStarted(0))
	{
		if(!LaunchBlueSoleil())
		{
			GYMsgBox(IDS_BT_START_BTDEV_DRIVE, MB_OK|MB_ICONWARNING);
			return FALSE;
		}
	}
	
	int nTryTimes = 0;
	while(!BT_IsBlueSoleilStarted(0) && nTryTimes++ < 10)
		Sleep(500);

	if(BT_InitializeLibrary())
	{
		DWORD dwResult = BT_RegisterCallback(EVENT_ERROR, GeneralError);
		dwResult=BT_RegisterCallback(EVENT_CONNECTION_STATUS, BTConnectCallback);
		if(dwResult != BTSTATUS_SUCCESS)
		{
			GYMsgBox(IDS_BT_DONGLE_NOT_READY, MB_OK|MB_ICONSTOP);
			return FALSE;
		}
	}
	else
	{
		BT_UninitializeLibrary();
		GYMsgBox(IDS_INIT_BTH_FAIL, MB_OK|MB_ICONSTOP);
		return FALSE;
	}

	return TRUE;
}

UINT CWAManager::InquireBTDeviceThread(LPVOID lpParam)
{
	CWAManager* pThis = (CWAManager*)lpParam;
	ASSERT(pThis);

	for(;;)
	{
		DWORD dwWaitRet = WaitForSingleObject(pThis->m_hEventInquireWA, INFINITE);
		if(dwWaitRet != WAIT_OBJECT_0)
			break;

		if(g_bAppQuit)
			break;

		pThis->m_bInquiringWA = TRUE;
		pThis->EnterBTCS();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		if(!BT_IsBlueSoleilStarted(1))
		{
			BT_StartBluetooth();
		}

		//  Check devices NOT been connected
		BT_DEV_INFO_VECTOR		vecDevInfo;

		UCHAR					ucInqMode = INQUIRY_GENERAL_REFRESH;
		UCHAR					ucInqLen = 15;
		BLUETOOTH_DEVICE_INFO	lpDevsList[MAX_SERVICE_COUNT] = {0};
		DWORD					DevsListLen = sizeof(BLUETOOTH_DEVICE_INFO) * MAX_SERVICE_COUNT;
		
		DWORD dwResult = BT_InquireDevices(ucInqMode, ucInqLen,  &DevsListLen, lpDevsList); // if DevsListLen == 0, it will be Asynchronous
		if(dwResult == BTSTATUS_SUCCESS)
		{
			int nDevCount = DevsListLen/sizeof(BLUETOOTH_DEVICE_INFO);
			for(int i = 0; i < nDevCount; i++)
				pThis->VerifyBTDevice(&vecDevInfo, lpDevsList[i].address);
		}

		//  Check devices ALREADY been connected
		GENERAL_CONNECT_INFO	connList[MAX_CONNECT_COUNT] = {0};

		DWORD dwSize	= sizeof(connList);
		dwResult		= BT_EnumConnections(&dwSize,connList);
		if(dwResult == BTSTATUS_SUCCESS)
		{
			int nConnCount = dwSize/sizeof(GENERAL_CONNECT_INFO);
			for(int i = 0; i < nConnCount; i++)
				pThis->VerifyBTDevice(&vecDevInfo, connList[i].remoteBdAddr);
		}
		
		//  Update devices list
		pThis->UpdateDevList(&vecDevInfo);

		if(pThis->GetWADeviceCount() < 1)
		{
			CString strMsg = GetResString(IDS_BT_WA_NOT_FOUND);
			GetApp()->GetCustMsgCenter()->PostStringMessage(GYWA_MSG_BLUETOOTH_CONNECT_PROGRESS, strMsg, 15000);
		}

		if(!pThis->m_bInquireTimerStarted)
		{
			GetApp()->GetCustMsgCenter()->StartTimer(GYWA_MSG_BLUETOOTH_TIMERID_INQUIRE_WA, 1000 * 60 * 3);
			pThis->m_bInquireTimerStarted = TRUE;
		}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pThis->LeaveBTCS();
		pThis->m_bInquiringWA = FALSE;
	}

	return 0;
}

BOOL CWAManager::AddWADevice(BLUETOOTH_DEVICE_INFO_EX* pDevInfo)
{
	BOOL bRet = FALSE;

	CWADevice* pWADev = new CWADevice(pDevInfo);
	if(pWADev)
	{
		m_vecWADevice.push_back(pWADev);
		pWADev->InitDev();
		bRet = TRUE;
	}

	return bRet;
}

BOOL CWAManager::IsGYWADevice(char* pDevName)
{
	if(strlen(pDevName) == 0)
		return FALSE;

	if(strnicmp(pDevName, GY_WA_NAME1, strlen(GY_WA_NAME1)) ==0 || strnicmp(pDevName, GY_WA_NAME2, strlen(GY_WA_NAME2)) == 0)
	{
		return TRUE;
	}

	return FALSE;
}

BOOL CWAManager::EnterBTCS()
{
	EnterCriticalSection(&m_csBluetoothToken);
	return TRUE;
}

BOOL CWAManager::LeaveBTCS()
{
	LeaveCriticalSection(&m_csBluetoothToken);
	return TRUE;
}

void CWAManager::GeneralError(DWORD dwErrorCode)
{
	DWORD dwErrorCodeGet = dwErrorCode;
}

void CWAManager::BTConnectCallback(WORD wServiceClass, BYTE* lpBdAddr, UCHAR ucStatus, DWORD dwConnetionHandle)
{
	switch(ucStatus)
	{
	case STATUS_INCOMING_CONNECT:
	case STATUS_INCOMING_DISCONNECT:
	case STATUS_OUTGOING_CONNECT:
		break;
	case STATUS_OUTGOING_DISCONNECT:
		{
			CWAManager* pThis = GetApp()->GetWAMan();
			if(pThis && !g_bAppQuit)
			{
				EnterCriticalSection(&pThis->m_csVectorDevList);
				
				for(int j = 0; j < pThis->m_vecWADevice.size(); j++)
				{
					if(pThis->m_vecWADevice[j])
					{
						BYTE aBTAddress[DEVICE_ADDRESS_LENGTH] = {0};
						pThis->m_vecWADevice[j]->GetAddress(aBTAddress);
						
						if(memcmp(aBTAddress, lpBdAddr, DEVICE_ADDRESS_LENGTH) == 0)
						{
							if(!pThis->m_vecWADevice[j]->IsDisconnBeforeConn())
							{
								pThis->m_vecWADevice[j]->SetConnectedWA(FALSE);
								pThis->m_vecWADevice[j]->SetBlueToothConnect(FALSE);

								//  Use send, not post
								GetApp()->GetCustMsgCenter()->SendCustMessage(GYWA_MSG_BLUETOOTH_REMOVE_DEV, (WPARAM)j, NULL);
								pThis->m_vecWADevice[j]->UninitDev();
								SAFE_DELETE(pThis->m_vecWADevice[j]);
							}

							break;
						}
					}
				}
				
				LeaveCriticalSection(&pThis->m_csVectorDevList);
			}
		}
		break;
	}
}

void CWAManager::OnTimerInquireWA(WPARAM wParam, LPARAM lParam)
{
	if(!m_bInquiringWA && m_hEventInquireWA && !g_bAppQuit)
	{
		SetEvent(m_hEventInquireWA);
	}
}

void CWAManager::OnWAConnected(WPARAM wParam, LPARAM lParam)
{
	CWADevice* pDevice = (CWADevice*)wParam;
	int nDevIndex = -1;
	for(int i = 0; i < m_vecWADevice.size(); i++)
	{
		if(m_vecWADevice[i] && m_vecWADevice[i] == pDevice)
		{
			nDevIndex = i;
			break;
		}
	}

	if(nDevIndex < 0)
		return;

	if(pDevice)
	{
		DWORD	dwCommVer = GetWACommVersion(nDevIndex);
		BOOL	bConnOK = cmdConnectWA(nDevIndex);
		if(!bConnOK)
		{
			//  try refresh comm version again
			dwCommVer	= cmdReadCommVersion(nDevIndex);
			bConnOK		= cmdConnectWA(nDevIndex);
			
			if(!bConnOK)
				GYMsgBox(IDS_CONNECT_WA_FAIL, MB_OK|MB_ICONSTOP);
		}
		else
		{
			GetApp()->GetCustMsgCenter()->PostCustMessage(GYWA_MSG_BLUETOOTH_FOUND_NEWDEV, (WPARAM)nDevIndex, NULL);

			BOOL bAllConnect = TRUE;
			for(int i = 0; i < m_vecWADevice.size(); i++)
			{
				if(m_vecWADevice[i] && !m_vecWADevice[i]->IsConnectedWA())
				{
					bAllConnect = FALSE;
					break;
				}
			}

			if(bAllConnect)
			{
				CString strMsg;
				strMsg.Format(GetResString(IDS_BT_ALLCONNECTOK), GetWADeviceCount());
				GetApp()->GetCustMsgCenter()->PostStringMessage(GYWA_MSG_BLUETOOTH_CONNECT_PROGRESS, strMsg, 10000);
			}
		}
	}
}

//  connect failed, remove device from vector
void CWAManager::OnWAConnectBTFail(WPARAM wParam, LPARAM lParam)
{
	CWADevice* pDevice = (CWADevice*)wParam;
	int nDevIndex = -1;
	for(int i = 0; i < m_vecWADevice.size(); i++)
	{
		if(m_vecWADevice[i] && m_vecWADevice[i] == pDevice)
		{
			nDevIndex = i;
			break;
		}
	}
	
	if(nDevIndex < 0)
		return;
	
	if(pDevice)
	{
		m_vecWADevice[i]->UninitDev();
		SAFE_DELETE(m_vecWADevice[i]);
	}
}

BOOL CWAManager::RemoveDeviceFromList(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_FALSE(pDevice);

	OnWAConnectBTFail((WPARAM)pDevice, NULL);
	return TRUE;
}

CString CWAManager::GetWADevName(int nDevIndex)
{
	CHECK_VECTOR_INDEX_STRING(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_EMPTY(pDevice);
	
	return pDevice->GetName();
}

DWORD CWAManager::GetWACommVersion(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);
	
	DWORD dwVer = pDevice->GetCommVersion();
	if(dwVer > 0)
		return dwVer;

	return cmdReadCommVersion(nDevIndex);
}

CString CWAManager::GetWAAddress(int nDevIndex)
{
	CHECK_VECTOR_INDEX_STRING(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_EMPTY(pDevice);
	
	return pDevice->GetAddress();
}

CString CWAManager::GetWADevID(int nDevIndex)
{
	CHECK_VECTOR_INDEX_STRING(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_EMPTY(pDevice);

	CString strDevID = pDevice->GetDevID();
	if(strDevID.IsEmpty())
	{
		strDevID = cmdReadWADevID(nDevIndex);
		pDevice->SetDevID(strDevID);
	}

	return strDevID;
}

BOOL CWAManager::IsWAConnected(int nDevIndex)
{
	if(nDevIndex >= 0 && nDevIndex < m_vecWADevice.size())
	{
		CWADevice* pDev = m_vecWADevice[nDevIndex];
		if(pDev)
			return pDev->IsConnectedWA();
	}
	
	return FALSE;
}

BOOL CWAManager::IsAllWAConnected()
{
	for(int i = 0; i < m_vecWADevice.size(); i++)
	{
		CWADevice* pDev = m_vecWADevice[i];
		if(m_vecWADevice[i] && !pDev->IsConnectedWA())
			return FALSE;
	}

	return TRUE;
}

BOOL CWAManager::LaunchBlueSoleil()
{
	HKEY hKey = NULL;
	HRESULT hr = ::RegCreateKeyEx(HKEY_LOCAL_MACHINE, BLUESOLEIL_REG_KEY_PATH, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE, NULL, &hKey, NULL);
	if(ERROR_SUCCESS != hr)
		return FALSE;
	
	TCHAR	szBlueSoleil[MAX_PATH];
	DWORD	dwSize = sizeof(szBlueSoleil);
	hr = ::RegQueryValueEx(hKey, BLUESOLEIL_REG_KEY_NAME, NULL, NULL, (LPBYTE)szBlueSoleil, &dwSize);
	::RegCloseKey(hKey);
	
	if(ERROR_SUCCESS != hr)
		return FALSE;

	CString strBlueSoleil = szBlueSoleil;
	if(strBlueSoleil.Right(1) != _T("\\"))
		strBlueSoleil += _T("\\");

	strBlueSoleil += BLUESOLEIL_EXEFILE;

	TCHAR szCmdLine[MAX_PATH] = {0};
	_tcscpy(szCmdLine, strBlueSoleil);
	
	//  CreateProcess() will fail, unless this app has administrator priviledge
	HINSTANCE hInst  = ::ShellExecute(NULL, _T("Open"),  strBlueSoleil, NULL , NULL, SW_SHOWNORMAL);

	return ((int)hInst > 32);
}

int CWAManager::GetFirstDevIndex()
{
	return GetNextDevIndex(-1);
}

int	CWAManager::GetNextDevIndex(int nDevIndex)
{
	int nCount = m_vecWADevice.size();

	if(nDevIndex >= (nCount - 1))
	{
		return -1;
	}

	int nRet = nDevIndex + 1;
	while(nRet < m_vecWADevice.size() && m_vecWADevice[nRet] == NULL)
		nRet++;

	return nRet;
}

int	CWAManager::GetWADeviceCount()
{
	int nRet = 0;
	for(int i = 0; i < m_vecWADevice.size(); i++)
	{
		if(m_vecWADevice[i])
			nRet++;
	}

	return nRet;
}

BOOL CWAManager::UpdateDevList(std::vector<BLUETOOTH_DEVICE_INFO_EX>* pLatestDevList)
{
	NULL_RETURN_FALSE(pLatestDevList);
	EnterCriticalSection(&m_csVectorDevList);

	int nDevCount = GetWADeviceCount();

	//  Add dev newly found
	for(int i = 0; i < pLatestDevList->size() && !g_bAppQuit; i++)
	{
		BLUETOOTH_DEVICE_INFO_EX DevInfoEx = (*pLatestDevList)[i];
		BOOL bNewFound = TRUE;

		for(int j = 0; j < m_vecWADevice.size(); j++)
		{
			if(m_vecWADevice[j])
			{
				BYTE aBTAddress[DEVICE_ADDRESS_LENGTH] = {0};
				m_vecWADevice[j]->GetAddress(aBTAddress);
				
				if(memcmp(aBTAddress, DevInfoEx.address, DEVICE_ADDRESS_LENGTH) == 0)
				{
					bNewFound = FALSE;
					break;
				}
			}
		}

		if(bNewFound && nDevCount < MAX_SUPPORT_WA_COUNT)
		{
			AddWADevice(&DevInfoEx);
			nDevCount++;
		}
	}

	LeaveCriticalSection(&m_csVectorDevList);
	return TRUE;
}

DWORD CWAManager::GetLastWAError(int nDevIndex)
{
	CHECK_VECTOR_INDEX_NUMBER(m_vecWADevice, nDevIndex);
	CWADevice* pDevice = m_vecWADevice[nDevIndex];
	NULL_RETURN_ZERO(pDevice);

	return pDevice->GetLastWAError();
}

DWORD CWAManager::GetBCDValue(BYTE byteData)
{
	DWORD dwTen = ((byteData & 0xf0) >> 4) * 10;
	DWORD dwOne =  (byteData & 0x0f);

	return (dwTen + dwOne);
}

BYTE CWAManager::GetBCDByte(DWORD dwData)
{
	dwData			= (dwData & 0xff);

	BYTE byteHigh	= ((dwData / 10) << 4);
	BYTE byteLow	= (dwData % 10);

	return (byteHigh | byteLow);
}

BOOL CWAManager::VerifyBTDevice(BT_DEV_INFO_VECTOR* pVecDev, BYTE* pBTDevAddress)
{
	BLUETOOTH_DEVICE_INFO_EX devInfoEx = {0};
	devInfoEx.dwSize = sizeof(BLUETOOTH_DEVICE_INFO_EX);
	memcpy(devInfoEx.address, pBTDevAddress, DEVICE_ADDRESS_LENGTH);
	
	DWORD dwMask = MASK_DEVICE_NAME|MASK_DEVICE_CLASS|MASK_CONNECT_STATUS|MASK_PAIR_STATUS;
	DWORD dwGetResult = BT_GetRemoteDeviceInfo(dwMask, &devInfoEx);
	
	if(dwGetResult != BTSTATUS_SUCCESS || strlen(devInfoEx.szName) <= 0)
		return FALSE;
	
	if(IsGYWADevice(devInfoEx.szName))
	{
		//  check whether it is already in vector
		BOOL bFound = FALSE;
		for(int i = 0; i < pVecDev->size(); i++)
		{
			if(memcmp((*pVecDev)[i].address, pBTDevAddress, DEVICE_ADDRESS_LENGTH) == 0)
			{
				bFound = TRUE;
				break;
			}
		}

		if(!bFound)
			pVecDev->push_back(devInfoEx);
	}

	return TRUE;
}
